<?xml version="1.0" encoding="windows-1251"?>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">

<html lang="ru" xml:lang="ru">

<head>
  <meta http-equiv="Content-type" content="text/html; charset=windows-1251" />
  <title>Basis Test Suite - DOM Wrapers</title>

  <style type="text/css">
    @import "style/default/style.css";

    /* */
    BODY
    {
      font-family: Georgia;
      font-size: small;
      _font-size: x-small;
    }
  </style>
  
  <script type="text/javascript"  src="../basis-all.js"></script>
  <script type="text/javascript"  src="test.js"></script>
  <script type="text/javascript"  src="common.js"></script>
</head>

<body>

  <script type="text/javascript">
    loadTest((function(){

      var Class = basis.Class;
      var DOM = basis.dom;
      var Data = basis.data;
      var CSS = basis.cssom;
      var Event = basis.dom.event;
      var Tester = basis.test.Tester;

      var nsWrappers = basis.dom.wrapper;
      var Property = basis.data.property.Property;
      var PropertySet = basis.data.property.DataObjectSet;

      var Node = nsWrappers.Node;

      var CookieName;
      var TestProperty;

      var updateCount = 0;

      //basis.event.EventObject.prototype.event_debug = function(e){
      //  console.log(e.sender.eventObjectId, e.type, e.args);
      //}

      var groupDatasetByGroupMap = {};
      var groupDatasetByGroup10 = new basis.data.Dataset({
        items: Array.create(10, function(idx){
          return groupDatasetByGroupMap[idx + 1] = new basis.data.DataObject({
            data: {
              id: idx + 1,
              title: idx + 1
            }
          })
        })
      });
      var groupDatasetByGroup = new basis.data.Dataset({
        items: Array.create(4, function(idx){
          return groupDatasetByGroupMap[idx + 1]
        })
      });


      var testSet = [
        { data: { title: 'node0', value: 0, group: 1 } },
        { data: { title: 'node1', value: 1, group: 2 } },
        { data: { title: 'node2', value: 2, group: 1 } },
        { data: { title: 'node3', value: 3, group: 3 } },
        { data: { title: 'node4', value: 4, group: 4 } },
        { data: { title: 'node5', value: 5, group: 2 } },
        { data: { title: 'node6', value: 6, group: 2 } },
        { data: { title: 'node7', value: 7, group: 1 } },
        { data: { title: 'node8', value: 8, group: 3 } },
        { data: { title: 'node9', value: 9, group: 1 } }
      ].map(function(item){
        item.data.groupObj = groupDatasetByGroupMap[item.data.group];
        return item;
      });

      var convertToNode = Function.getter(Function.$self, testSet);

      function getTestSet(){
        return testSet.map(function(item){
          return {
            data: Object.slice(item.data)
          }
        });
      }

      function getDataset(){
        return new basis.data.Dataset({
          items: testSet.map(function(item){
            return new basis.data.DataObject({
              data: Object.slice(item.data)
            })
          })
        });
      }

      function nodeFactory(cfg){
        return new Node(cfg);
      };

      function getGroups(node, withNull){
        var res = Array.from(node.grouping.childNodes);
        if (withNull)
          res.unshift(node.grouping.nullGroup);
        return res;
      }

      function checkOrder(nodes, host){
        var sortingValue = host.sorting;
        var desc = host.sortingDesc;

        for (var i = 0; i < nodes.length; i++)
          if (nodes[i].sortingValue !== sortingValue(nodes[i]))
            return 'Bad sortingValue';

        if (!desc)
        {
          for (var i = 0; i < nodes.length - 1; i++)
            if (nodes[i].sortingValue > nodes[i + 1].sortingValue)
              return 'Wrong order';
        }
        else
        {
          for (var i = 0; i < nodes.length - 1; i++)
            if (nodes[i].sortingValue < nodes[i + 1].sortingValue)
              return 'Wrong order';
        }
      }

      function checkNode(node){
        var res;

        if (node.childNodes)
        {
          var childCount = node.childNodes.length;

          if (node.firstChild !== (node.childNodes[0] || null))
            return 'Wrong firstChild ref';
          if (node.lastChild !== (node.childNodes[childCount - 1] || null))
            return 'Wrong lastChild ref';

          for (var i = 0; i < childCount; i++)
          {
            var child = node.childNodes[i];

            if (child.parentNode !== node)
              return 'child #' + i + ' has wrong parentNode ref';

            if (i > 0)
            {
              if (child.previousSibling !== node.childNodes[i - 1])
              {
                return 'child #' + i + ' has wrong previousSibling ref';
              }
            }
            else
            {
              if (child.previousSibling !== null)
                return 'child #' + i + ' has wrong previousSibling ref, must be a null';
            }

            if (i < childCount - 1)
            {
              if (child.nextSibling !== node.childNodes[i + 1])
                return 'child #' + i + ' has wrong nextSibling ref';
            }
            else
            {
              if (child.nextSibling !== null)
                return 'child #' + i + ' has wrong nextSibling ref, must be a null';
            }
            //if (child.document != node.document)
            //  return 'child #' + i + ' has wrong document ref';
          }

          if (node.sorting !== Function.nullGetter)
          {
            if (node.grouping)
            {
              var groups = getGroups(node, true);
              for (var i = 0; i < groups.length; i++)
                if (res = checkOrder(groups[i].nodes, node))
                  return 'Sorting in group: ' + res;
            }
            else
              if (res = checkOrder(node.childNodes, node))
                return 'Sorting: ' + res;
          }

          if (node.grouping)
          {
            if (res = checkNode(node.grouping))
              return res;

            var groups = getGroups(node, true);
            for (var i = 0; i < groups.length; i++)
            {
              if (res = checkNode(groups[i]))
                return 'group #' + i + ': ' + res;
            }

            for (var i = 0, k = 0, group; group = groups[i++];)
              for (var j = 0, groupNode; groupNode = group.nodes[j++];)
                if (node.childNodes[k++] !== groupNode)
                  return 'Wrong order: childs not reflect groups order';

            if (k != childCount)
            {
              return 'Count of child in groups (' + k + ') is not equal to child count (' + childCount + ')';
            }

            var childNodes = Array.from(node.childNodes);

            // check for child groupNode reference
            for (var i = 0, child; child = node.childNodes[i++];)
              if (node.grouping.getGroupNode(child, true) !== child.groupNode)
                return 'child node has wrong groupNode ref';

            // after getGroupNode node.childNodes and groups must not be changed
            var currentGroups = getGroups(node, true);

            if (childCount !== node.childNodes.length)
              return 'childNodes broken after getGroupNode for childs';
            if (currentGroups.length !== groups.length)
              return 'groups broken after getGroupNode for childs';

            for (var i = 0; i < childNodes.length; i++)
              if (childNodes[i] !== node.childNodes[i])
                return 'childNodes broken after getGroupNode for childs';

            for (var i = 0; i < groups.length; i++)
              if (groups[i] !== currentGroups[i])
                return 'groups broken after getGroupNode for childs';
          }
          else
          {
            for (var i = 0, child; child = node.childNodes[i++];)
              if (child.groupNode !== null)
                return 'child node has wrong groupNode ref, must be a null';
          }
        }
        else
        {
          if (node.firstChild !== null)
            return 'Wrong firstChild ref';
          if (node.lastChild !== null)
            return 'Wrong lastChild ref';
        }

        if (node.dataSource !== null && node.dataSource instanceof basis.data.AbstractDataset === false)
          return 'dataSource has wrong value (must be null or instance of basis.data.AbstractDataset)';

        if (node.dataSource)
        {
          if (node.dataSource.itemCount !== node.childNodes.length)
            return 'child node count (' + node.childNodes.length + ') is not equal to dataset item count (' + node.dataSource.itemCount + ')';

          for (var i = 0, child; child = node.childNodes[i]; i++)
          {
            if (!child.delegate)
              return 'child #' + i + ' has not delegate to dataSource member';

            if (!node.dataSource.has(child.delegate))
              return 'child #' + i + ' delegate not found in dataSource';
          }
        }

        if (node instanceof nsWrappers.GroupingNode)
        {
          if (node.owner && node.owner.grouping !== node)
              return 'wrong GroupingNode.owner ref';
        }

        if (node instanceof nsWrappers.PartitionNode)
        {
          if (!node.nodes)
            return 'PartitionNode has no child nodes';

          var nodeCount = node.nodes.length;

          if (nodeCount)
          {
            if (node.first !== node.nodes[0])
              return 'wrong PartitionNode.first ref';

            if (node.last !== node.nodes[nodeCount - 1])
              return 'wrong PartitionNode.last ref';

            var hostNode = node.first.parentNode;
            var childNodesIndex = hostNode.childNodes.indexOf(node.first);

            for (var i = 0; i < node.nodes.length; i++)
              if (node.nodes[i] !== hostNode.childNodes[childNodesIndex + i])
                return 'wrong PartitionNode.nodes order';
          }
          else
          {
            if (node.first !== null)
              return 'wrong PartitionNode.first ref, must be a null';

            if (node.last !== null)
              return 'wrong PartitionNode.last ref, must be a null';
          }
        }

        return false;
      }

      function checkDestroyedObject(object){
        var proto = object.constructor.prototype;
        var properties = [];

        for (var key in object)
        {
          var value = object[key];
          if (key !== 'data' && value !== proto[key] && typeof value == 'object' && value !== null)
            properties.push(key);
        }

        return properties.length
          ? 'properties are not reset in destroyed object: ' + properties.join(', ')
          : false;
      }

      function $values(ar){
        return ar.map(function(node){
          return node.data.value + '(' + node.data.group + ')';
        })
      }

      return [
        {
          name: 'DOM wrappers',
          testcase: [
            {
              name: 'basic',
              testcase: [
                {
                  name: 'create',
                  test: function(){
                    var node = new Node();
                    this.is(false, checkNode(node));

                    var node = new Node({ data: { a: 1, b: 2 } });
                    this.is({ a: 1, b: 2}, node.data);
                  }
                },
                {
                  name: 'create with childNodes',
                  test: function(){
                    var testSet = getTestSet();
                    var node = new Node({ childNodes: testSet.map(nodeFactory) });
                    this.is(false, checkNode(node));
                    this.is(testSet.length, node.childNodes.length);
                    this.is($values(testSet), $values(node.childNodes));

                    var testSet = getTestSet();
                    var node = new Node({ childFactory: nodeFactory, childNodes: testSet });
                    this.is(false, checkNode(node));
                    this.is(testSet.length, node.childNodes.length);
                    this.is($values(testSet), $values(node.childNodes));
                  }
                },
                {
                  name: 'appendChild',
                  test: function(){
                    var node = new Node();
                    var testSet = getTestSet();
                    for (var i = 0; i < testSet.length; i++)
                      node.appendChild(new Node(testSet[i]));
                    this.is(false, checkNode(node));
                    this.is(testSet.length, node.childNodes.length);
                    this.is($values(testSet), $values(node.childNodes));
                  }
                },
                {
                  name: 'insertBefore',
                  test: function(){
                    var testSet = getTestSet();
                    var node = new Node();
                    for (var i = 0; i < testSet.length; i++)
                      node.insertBefore(new Node(testSet[i]));

                    this.is(false, checkNode(node));
                    this.is(testSet.length, node.childNodes.length);
                    this.is($values(testSet), $values(node.childNodes));

                    var testSet = getTestSet();
                    var node = new Node();
                    for (var i = 0; i < testSet.length; i++)
                      node.insertBefore(new Node(testSet[i]), node.firstChild);

                    this.is(false, checkNode(node));
                    this.is(testSet.length, node.childNodes.length);
                    this.is($values(testSet).reverse(), $values(node.childNodes));
                  }
                },
                {
                  name: 'DOM.insert',
                  test: function(){
                    var testSet = getTestSet();
                    var node = new Node();
                    DOM.insert(node, testSet.map(nodeFactory))
                    this.is(false, checkNode(node));
                    this.is(testSet.length, node.childNodes.length);
                    this.is($values(testSet), $values(node.childNodes));

                    var testSet = getTestSet();
                    var node = new Node({ childFactory: nodeFactory });
                    DOM.insert(node, testSet)
                    this.is(false, checkNode(node));
                    this.is(testSet.length, node.childNodes.length);
                    this.is($values(testSet), $values(node.childNodes));
                  }
                }
              ]
            },
            {
              name: 'dataSource',
              testcase: [
                {
                  name: 'dataSource in config',
                  test: function(){
                    var testSet = getTestSet();
                    var dataset = getDataset();
                    var node = new Node({
                      childFactory: nodeFactory,
                      dataSource: dataset
                    });

                    this.is(false, checkNode(node));
                    this.is(true, testSet.length > 0);
                    this.is(dataset, node.dataSource);
                    this.is(testSet.length, node.childNodes.length);
                    this.is(testSet.length, dataset.itemCount);
                  }
                },
                {
                  name: 'if dataSource in config, childNodes must be ignored',
                  test: function(){
                    var testSet = getTestSet();
                    var dataset = getDataset();
                    var node = new Node({
                      childFactory: nodeFactory,
                      childNodes: testSet,
                      dataSource: dataset
                    });

                    this.is(false, checkNode(node));
                    this.is(dataset, node.dataSource);
                    this.is(dataset.itemCount, node.childNodes.length);
                  }
                },
                {
                  name: 'if dataSource set than node modify methods must throw an exception and must not to change childNodes or dataSource',
                  test: function(){
                    var dataset = getDataset();
                    var node = new Node({
                      childFactory: nodeFactory,
                      dataSource: dataset
                    });

                    this.is(dataset, node.dataSource);

                    var itemCount = dataset.itemCount;
                    var childNodes = Array.from(node.childNodes);

                    var exceptionHere = false;
                    try {
                      node.appendChild(new Node)
                    } catch(e){
                      exceptionHere = true;
                    }
                    this.is(dataset, node.dataSource);
                    this.is(itemCount, dataset.itemCount);
                    this.is(false, checkNode(node));
                    this.is(true, exceptionHere);

                    var exceptionHere = false;
                    try {
                      node.insertBefore(new Node)
                    } catch(e){
                      exceptionHere = true;
                    }
                    this.is(dataset, node.dataSource);
                    this.is(itemCount, dataset.itemCount);
                    this.is(false, checkNode(node));
                    this.is(true, exceptionHere);

                    var exceptionHere = false;
                    try {
                      node.removeChild(node.firstChild)
                    } catch(e){
                      exceptionHere = true;
                    }
                    this.is(dataset, node.dataSource);
                    this.is(itemCount, dataset.itemCount);
                    this.is(false, checkNode(node));
                    this.is(true, exceptionHere);

                    var exceptionHere = false;
                    try {
                      node.replaceChild(new Node, node.firstChild)
                    } catch(e){
                      exceptionHere = true;
                    }
                    this.is(dataset, node.dataSource);
                    this.is(itemCount, dataset.itemCount);
                    this.is(false, checkNode(node));
                    this.is(true, exceptionHere);
                  }
                },
                {
                  name: 'clear with dataSource',
                  test: function(){
                    var dataset = getDataset();
                    var node = new Node({
                      childFactory: nodeFactory,
                      dataSource: dataset
                    });

                    var itemCount = dataset.itemCount;

                    this.is(dataset, node.dataSource);

                    var exceptionHere = false;
                    try {
                      node.clear();
                    } catch(e){
                      exceptionHere = true;
                    }
                    this.is(dataset, node.dataSource);
                    this.is(itemCount, dataset.itemCount);
                    this.is(false, checkNode(node));
                    this.is(true, exceptionHere);

                    // no exception if dataSource is empty
                    dataset.clear();
                    var exceptionHere = false;
                    try {
                      node.clear();
                    } catch(e){
                      exceptionHere = true;
                    }
                    this.is(dataset, node.dataSource);
                    this.is(0, dataset.itemCount);
                    this.is(false, checkNode(node));
                    this.is(false, exceptionHere);
                  }
                },
                {
                  name: 'setChildNodes with dataSource',
                  test: function(){
                    var dataset = getDataset();
                    var node = new Node({
                      childFactory: nodeFactory,
                      dataSource: dataset
                    });

                    var itemCount = dataset.itemCount;
                    this.is(dataset, node.dataSource);

                    var exceptionHere = false;
                    try {
                      node.setChildNodes([new Node]);
                    } catch(e){
                      exceptionHere = true;
                    }
                    this.is(dataset, node.dataSource);
                    this.is(itemCount, dataset.itemCount);
                    this.is(false, checkNode(node));
                    this.is(true, exceptionHere);
                  }
                },
                {
                  name: 'insertBefore(node/config) must throw exception if child with delegate->dataSource.item already exists',
                  test: function(){
                    var dataset = getDataset();
                    var node = new Node({
                      childFactory: nodeFactory,
                      dataSource: dataset
                    });
                    
                    var itemCount = dataset.itemCount;
                    this.is(dataset, node.dataSource);
                    this.is(true, itemCount > 0);
                    
                    var exceptionHere = false;
                    try {
                      node.insertBefore(dataset.pick());
                    } catch(e){
                      exceptionHere = true;
                    }
                    this.is(dataset, node.dataSource);
                    this.is(itemCount, dataset.itemCount);
                    this.is(false, checkNode(node));
                    this.is(true, exceptionHere);

                    var exceptionHere = false;
                    try {
                      node.insertBefore({ delegate: dataset.pick() });
                    } catch(e){
                      exceptionHere = true;
                    }
                    this.is(dataset, node.dataSource);
                    this.is(itemCount, dataset.itemCount);
                    this.is(false, checkNode(node));
                    this.is(true, exceptionHere);

                    var exceptionHere = false;
                    try {
                      node.insertBefore(new Node({ delegate: dataset.pick() }));
                    } catch(e){
                      exceptionHere = true;
                    }
                    this.is(dataset, node.dataSource);
                    this.is(itemCount, dataset.itemCount);
                    this.is(false, checkNode(node));
                    this.is(true, exceptionHere);
                  }
                },
                {
                  name: 'set/reset/set dataSource',
                  test: function(){
                    var testSet = getTestSet();
                    var dataset = getDataset();
                    var node = new Node({
                      childFactory: nodeFactory
                    });

                    node.setDataSource(dataset);
                    this.is(false, checkNode(node));
                    this.is(dataset, node.dataSource);
                    this.is(dataset.itemCount, node.childNodes.length);

                    node.setDataSource();
                    this.is(false, checkNode(node));
                    this.is(null, node.dataSource);
                    this.is(0, node.childNodes.length);

                    node.setDataSource(dataset);
                    this.is(false, checkNode(node));
                    this.is(dataset, node.dataSource);
                    this.is(dataset.itemCount, node.childNodes.length);
                  }
                },
                {
                  name: 'set/reset dataSource/childNodes',
                  test: function(){
                    var testSet = getTestSet();
                    var dataset = getDataset();
                    var node = new Node({
                      childFactory: nodeFactory,
                      childNodes: testSet
                    });
                    this.is(false, checkNode(node));
                    this.is(testSet.length, node.childNodes.length);

                    node.setDataSource(dataset);
                    this.is(false, checkNode(node));
                    this.is(dataset, node.dataSource);
                    this.is(dataset.itemCount, node.childNodes.length);

                    node.setDataSource();
                    this.is(false, checkNode(node));
                    this.is(null, node.dataSource);
                    this.is(0, node.childNodes.length);

                    node.setChildNodes(testSet);
                    this.is(false, checkNode(node));
                    this.is(testSet.length, node.childNodes.length);

                    node.setDataSource(dataset);
                    this.is(false, checkNode(node));
                    this.is(dataset, node.dataSource);
                    this.is(dataset.itemCount, node.childNodes.length);

                  }
                },
                {
                  name: 'set dataSource and destroy dataSource',
                  test: function(){
                    var dataset = getDataset();
                    var node = new Node({
                      childFactory: nodeFactory,
                      dataSource: dataset
                    });

                    var itemCount = dataset.itemCount;

                    this.is(dataset, node.dataSource);
                    this.is(true, itemCount > 0);
                    this.is(false, checkNode(node));

                    dataset.destroy();

                    this.is(null, node.dataSource);
                    this.is(false, checkNode(node));
                  }
                }
              ]
            },
            {
              name: 'sorting',
              testcase: []
            },
            {
              name: 'grouping',
              testcase: [
                {
                  name: 'grouping in config',
                  test: function(){
                    var testSet = getTestSet();
                    var node = new Node({
                      childFactory: nodeFactory,
                      grouping: 'data.group'
                    });

                    for (var i = 0; i < testSet.length; i++)
                      node.appendChild(testSet[i]);

                    this.is(false, checkNode(node));
                    this.is($values(testSet.sortAsObject('data.group')), $values(node.childNodes));

                    // =======================================
                    var testSet = getTestSet();
                    var node = new Node({
                      childFactory: nodeFactory,
                      grouping: {
                        groupGetter: Function.getter('data.group'),
                        sorting: Function.getter('data.id'),
                        sortingDesc: true
                      }
                    });

                    for (var i = 0; i < testSet.length; i++)
                      node.appendChild(testSet[i]);

                    this.is(false, checkNode(node));
                    this.is($values([4, 3, 8, 1, 5, 6, 0, 2, 7, 9].map(convertToNode)), $values(node.childNodes));

                    // ======================================
                    var testSet = getTestSet();
                    var node = new Node({
                      childFactory: nodeFactory,
                      sorting: Function.getter('data.value'),
                      sortingDesc: true,
                      grouping: {
                        groupGetter: Function.getter('data.group'),
                        sorting: Function.getter('data.id'),
                        sortingDesc: true
                      },
                      childNodes: testSet
                    });

                    this.is(false, checkNode(node));
                    this.is($values([4, 8, 3, 6, 5, 1, 9, 7, 2, 0].map(convertToNode)), $values(node.childNodes));
                  }
                },
                {
                  name: 'update PartitionNode',
                  test: function(){
                    // ======================================
                    var testSet = getTestSet();
                    var node = new Node({
                      childFactory: nodeFactory,
                      sorting: Function.getter('data.value'),
                      sortingDesc: true,
                      grouping: {
                        groupGetter: Function.getter('data.group'),
                        sorting: Function.getter('data.title', String),
                        sortingDesc: true
                      },
                      childNodes: testSet
                    });

                    this.is(false, checkNode(node));
                    this.is($values([4, 8, 3, 6, 5, 1, 9, 7, 2, 0].map(convertToNode)), $values(node.childNodes));

                    var groups = getGroups(node);
                    for (var i = 0; i < groups.length; i++)
                      groups[i].update({ title: 'group' + groups[i].data.title });

                    this.is(false, checkNode(node));
                    this.is($values([4, 8, 3, 6, 5, 1, 9, 7, 2, 0].map(convertToNode)), $values(node.childNodes));

                    groups[0].update({ title: '-1' });
                    this.is(false, checkNode(node));
                    this.is($values([8, 3, 6, 5, 1, 9, 7, 2, 0, 4].map(convertToNode)), $values(node.childNodes));

                    groups[1].update({ title: '-2' });
                    this.is(false, checkNode(node));
                    this.is($values([6, 5, 1, 9, 7, 2, 0, 8, 3, 4].map(convertToNode)), $values(node.childNodes));

                    groups[2].update({ title: '-3' });
                    this.is(false, checkNode(node));
                    this.is($values([9, 7, 2, 0, 6, 5, 1, 8, 3, 4].map(convertToNode)), $values(node.childNodes));

                    groups[3].update({ title: '-4' });
                    this.is(false, checkNode(node));
                    this.is($values([9, 7, 2, 0, 6, 5, 1, 8, 3, 4].map(convertToNode)), $values(node.childNodes));
                  }
                },
                {
                  name: 'update PartitionNode with delegate',
                  test: function(){
                    var groupNodes = {};
                    for (var i = 1; i <= 4; i++)
                      groupNodes[i] = new Node({
                        data: {
                          title: i
                        }
                      });

                    // ======================================
                    var node = new Node({
                      childFactory: nodeFactory,
                      sorting: Function.getter('data.value'),
                      sortingDesc: true,
                      grouping: {
                        groupGetter: Function.getter('data.group', groupNodes),
                        sorting: Function.getter('data.title'),
                        sortingDesc: true
                      },
                      childNodes: testSet//.filter(Function.getter('data.group >= 3'))
                    });

                    this.is(false, checkNode(node));
                    this.is(4, getGroups(node).length);
                    this.is($values([4, 8, 3, 6, 5, 1, 9, 7, 2, 0].map(convertToNode)), $values(node.childNodes));

                    var groups = getGroups(node);
                    /*for (var i = 0; i < groups.length; i++)
                      groups[i].update({ title: 'group' + i });*/

                    groups[0].update({ title: -4 });
                    this.is(false, checkNode(node));
                    this.is($values([8, 3, 6, 5, 1, 9, 7, 2, 0, 4].map(convertToNode)), $values(node.childNodes));

                    groups[1].update({ title: -3 });
                    this.is(false, checkNode(node));
                    this.is($values([6, 5, 1, 9, 7, 2, 0, 8, 3, 4].map(convertToNode)), $values(node.childNodes));

                    groups[2].update({ title: -2 });
                    this.is(false, checkNode(node));
                    this.is($values([9, 7, 2, 0, 6, 5, 1, 8, 3, 4].map(convertToNode)), $values(node.childNodes));

                    groups[3].update({ title: -1 });
                    this.is(false, checkNode(node));
                    this.is($values([9, 7, 2, 0, 6, 5, 1, 8, 3, 4].map(convertToNode)), $values(node.childNodes));

                  }
                },
                {
                  name: 'setGrouping after create and update PartitionNode with delegate',
                  test: function(){

                    var groupNodes = {};
                    for (var i = 1; i <= 4; i++)
                      groupNodes[i] = new Node({
                        data: {
                          title: i
                        }
                      });


                    var node = new Node({
                      childFactory: nodeFactory,
                      sorting: Function.getter('data.value'),
                      sortingDesc: true,
                      childNodes: testSet//.filter(Function.getter('data.group >= 3'))
                    });

                    this.is(false, checkNode(node));

                    node.setGrouping({
                      groupGetter: Function.getter('data.group', groupNodes),
                      sorting: Function.getter('data.title'),
                      sortingDesc: true
                    });

                    this.is(false, checkNode(node));
                    this.is(4, getGroups(node).length);
                    this.is($values([4, 8, 3, 6, 5, 1, 9, 7, 2, 0].map(convertToNode)), $values(node.childNodes));

                    var groups = getGroups(node);
                    /*for (var i = 0; i < groups.length; i++)
                      groups[i].update({ title: 'group' + i });*/

                    groups[0].update({ title: -4 });
                    this.is(false, checkNode(node));
                    this.is($values([8, 3, 6, 5, 1, 9, 7, 2, 0, 4].map(convertToNode)), $values(node.childNodes));

                    groups[1].update({ title: -3 });
                    this.is(false, checkNode(node));
                    this.is($values([6, 5, 1, 9, 7, 2, 0, 8, 3, 4].map(convertToNode)), $values(node.childNodes));

                    groups[2].update({ title: -2 });
                    this.is(false, checkNode(node));
                    this.is($values([9, 7, 2, 0, 6, 5, 1, 8, 3, 4].map(convertToNode)), $values(node.childNodes));

                    groups[3].update({ title: -1 });
                    this.is(false, checkNode(node));
                    this.is($values([9, 7, 2, 0, 6, 5, 1, 8, 3, 4].map(convertToNode)), $values(node.childNodes));
                  }
                },
                {
                  name: 'setGrouping after create and update PartitionNode with delegate & subscription',
                  test: function(){

                    var groupDelegateClass = Class(Node, {
                      event_subscribersChanged: function(obj){
                        Node.prototype.event_subscribersChanged.call(this, obj);
                        if (this.subscriberCount)
                          this.update({ title: this.data.title_ });
                      }
                    })

                    var groupNodes = {};
                    for (var i = 1; i <= 4; i++)
                      groupNodes[i] = new groupDelegateClass({
                        data: {
                          title_: -i,
                          title: i
                        }
                      });


                    var node = new Node({
                      childFactory: nodeFactory,
                      sorting: Function.getter('data.value'),
                      sortingDesc: true,
                      groupingClass: {
                        childClass: {
                          active: true
                        }
                      },
                      childNodes: testSet//.filter(Function.getter('data.group >= 3'))
                    });

                    this.is(false, checkNode(node));

                    node.setGrouping({
                      groupGetter: Function.getter('data.group', groupNodes),
                      sorting: Function.getter('data.title'),
                      sortingDesc: true
                    });

                    this.is(false, checkNode(node));
                    this.is(4, getGroups(node).length);
                    this.is($values([9, 7, 2, 0, 6, 5, 1, 8, 3, 4].map(convertToNode)), $values(node.childNodes));
                  }
                }
              ]
            },
            {
              name: 'Dynamic test',
              testcase: [
                {
                  name: 'set sorting',
                  test: function(){
                    var node = new Node({
                      childFactory: nodeFactory,
                      childNodes: getTestSet()
                    });

                    this.is(false, checkNode(node));

                    node.setSorting(Function.getter('data.value'));
                    this.is(false, checkNode(node));

                    var order = Array.from(node.childNodes);
                    node.setSorting(Function.getter('data.value * -1'), true);
                    this.is(false, checkNode(node));
                    this.is(order, node.childNodes);

                    node.setSorting();
                    this.is(false, checkNode(node));

                    node.setSorting(Function.getter('data.value'), true);
                    this.is(false, checkNode(node));

                    var order = Array.from(node.childNodes);
                    for (var i = 0; i < order.length; i++)
                      order[i].update({ value: -order[i].data.value });
                    this.is(false, checkNode(node));
                    this.is(order.reverse(), node.childNodes);
                  },
                },
                {
                  name: 'set sorting #2',
                  test: function(){
                    var node = new Node({
                      childFactory: nodeFactory,
                      sorting: Function.getter('data.value'),
                      childNodes: getTestSet()
                    });
                    this.is(false, checkNode(node));

                    var node = new Node({
                      childFactory: nodeFactory,
                      sorting: Function.getter('data.value'),
                      sortingDesc: true,
                      childNodes: getTestSet()
                    });
                    this.is(false, checkNode(node));

                    var node = new Node({
                      childFactory: nodeFactory,
                      sorting: Function.getter('data.value'),
                      sortingDesc: true
                    });
                    this.is(false, checkNode(node));
                    node.setChildNodes(getTestSet());
                    this.is(false, checkNode(node));
                    node.clear();
                    this.is(false, checkNode(node));
                    node.setChildNodes(getTestSet());
                    this.is(false, checkNode(node));
                  }
                },
                {
                  name: 'set grouping',
                  testcase: [
                    {
                      name: 'set/remove, change grouping',
                      test: function(){
                        var node = new Node({
                          childFactory: nodeFactory,
                          childNodes: getTestSet()
                        });
                        this.is(false, checkNode(node));

                        node.setGrouping(Function.getter('data.group'));
                        this.is(false, checkNode(node));
                        this.is(4, getGroups(node).length);

                        // change grouping
                        node.setGrouping(Function.getter('data.value'));
                        this.is(false, checkNode(node));
                        this.is(10, getGroups(node).length);

                        // drop grouping
                        var order = Array.from(node.childNodes);
                        node.setGrouping();
                        this.is(false, checkNode(node));
                        this.is(null, node.grouping);
                        this.is(order, node.childNodes);

                        node.setGrouping({
                          groupGetter: Function.getter('data.value'),
                          sorting: Function.getter('data.title')
                        });
                        this.is(false, checkNode(node));

                        var order = Array.from(node.childNodes);
                        // nothing changed
                        node.grouping.setSorting(node.grouping.sorting);
                        this.is(false, checkNode(node));
                        this.is(order, node.childNodes);
                        // reverse order
                        node.grouping.setSorting(node.grouping.sorting, true);
                        this.is(false, checkNode(node));
                        this.is($values(order).reverse(), $values(node.childNodes));
                      }
                    },
                    {
                      name: 'set grouping and clear childNodes',
                      test: function(){
                        var node = new Node({
                          childFactory: nodeFactory,
                          grouping: {
                            groupGetter: Function.getter('data.value')
                          }
                        });
                        this.is(false, checkNode(node));

                        node.setChildNodes(getTestSet());
                        this.is(false, checkNode(node));

                        node.clear();
                        this.is(false, checkNode(node));

                        node.setChildNodes(getTestSet());
                        this.is(false, checkNode(node));
                      }
                    },
                    {
                      name: 'create with grouping and destroy grouping',
                      test: function(){
                        var node = new Node({
                          childFactory: nodeFactory,
                          grouping: {
                            groupGetter: Function.getter('data.value')
                          }
                        });

                        var grouping = node.grouping;
                        grouping.destroy();
                        this.is(true, node.grouping === null);
                        this.is(false, checkNode(node));
                        this.is(false, checkDestroyedObject(grouping));
                      }
                    },
                    {
                      name: 'set grouping and destroy grouping',
                      test: function(){
                        var node = new Node({
                          childFactory: nodeFactory
                        });

                        node.setGrouping('data.value');
                        this.is(true, node.grouping !== null);

                        var grouping = node.grouping;
                        grouping.destroy();
                        this.is(true, node.grouping === null);
                        this.is(false, checkNode(node));
                        this.is(false, checkDestroyedObject(grouping));
                      }
                    }
                  ]
                },
                {
                  name: 'nesting grouping',
                  testcase: [
                    {
                      name: 'create with nested grouping, decrease deep step by step, and increase back step by step',
                      test: function(){
                        var node = new Node({
                          childFactory: nodeFactory,
                          grouping: {
                            groupGetter: Function.getter('data.value'),
                            grouping: {
                              groupGetter: Function.getter('data.id % 4'),
                              grouping: Function.getter('data.id % 2')
                            }
                          },
                          childNodes: getTestSet()
                        });
                        this.is(false, checkNode(node));

                        node.grouping.grouping.setGrouping();
                        this.is(false, checkNode(node));

                        node.grouping.setGrouping();
                        this.is(false, checkNode(node));

                        node.setGrouping();
                        this.is(false, checkNode(node));

                        node.setGrouping('data.value');
                        this.is(false, checkNode(node));

                        node.grouping.setGrouping('data.id % 4');
                        this.is(false, checkNode(node));

                        node.grouping.grouping.setGrouping('data.id % 2');
                        this.is(false, checkNode(node));
                      }
                    },
                    {
                      name: 'set childs for node with nested grouping',
                      test: function(){
                        var node = new Node({
                          childFactory: nodeFactory,
                          grouping: {
                            groupGetter: Function.getter('data.value'),
                            grouping: {
                              groupGetter: Function.getter('data.id % 4'),
                              grouping: Function.getter('data.id % 2')
                            }
                          }
                        });

                        node.setChildNodes(getTestSet());
                        this.is(false, checkNode(node));

                        node.clear();
                        this.is(false, checkNode(node));

                        node.setChildNodes(getTestSet());
                        this.is(false, checkNode(node));

                        node.setGrouping();
                        this.is(false, checkNode(node));
                      }
                    },
                    {
                      name: 'increase deep of nested grouping step by step and reset',
                      test: function(){
                        var node = new Node({
                          childFactory: nodeFactory,
                          childNodes: getTestSet()
                        });
                        this.is(false, checkNode(node));

                        node.setGrouping('data.value');
                        this.is(false, checkNode(node));

                        node.grouping.setGrouping('data.id % 4');
                        this.is(false, checkNode(node));

                        node.grouping.grouping.setGrouping('data.id % 2');
                        this.is(false, checkNode(node));

                        node.setGrouping();
                        this.is(false, checkNode(node));
                      }
                    },
                    {
                      name: 'replace nested grouping by other',
                      test: function(){
                        var node = new Node({
                          childFactory: nodeFactory,
                          childNodes: getTestSet()
                        });
                        node.setGrouping({
                          groupGetter: Function.getter('data.value'),
                          grouping: {
                            groupGetter: Function.getter('data.id % 4'),
                            grouping: Function.getter('data.id % 2')
                          }
                        });
                        this.is(false, checkNode(node));

                        node.setGrouping('data.value');
                        this.is(true, node.grouping !== null);

                        node.setGrouping({
                          groupGetter: Function.getter('data.value'),
                          grouping: {
                            groupGetter: Function.getter('data.id % 4'),
                            grouping: Function.getter('data.id % 2')
                          }
                        });
                        this.is(false, checkNode(node));

                        node.setGrouping();
                        this.is(false, checkNode(node));
                      }
                    }
                  ]
                },
                {
                  name: 'mixing sorting & grouping',
                  test: function(){
                    var node = new Node({
                      childFactory: nodeFactory,
                      childNodes: getTestSet()
                    });

                    node.setGrouping(Function.getter('data.group'));
                    this.is(false, checkNode(node));

                    node.setSorting(Function.getter('data.value'));
                    this.is(false, checkNode(node));

                    node.setGrouping({
                      groupGetter: Function.getter('data.group'),
                      sorting: Function.getter('data.id'),
                      sortingDesc: true
                    });
                    this.is(false, checkNode(node));

                    node.setGrouping();
                    this.is(false, checkNode(node));

                    node.setSorting(Function.getter('data.group'), true);
                    this.is(false, checkNode(node));

                    node.setGrouping(Function.getter('data.group'));
                    this.is(false, checkNode(node));

                    var order = Array.from(node.childNodes);
                    node.setSorting();
                    this.is(false, checkNode(node));
                    node.setGrouping();
                    this.is(false, checkNode(node));
                    this.is(order, node.childNodes);
                  }
                },
                {
                  name: 'partition manipulations',
                  test: function(){
                    var node = new Node({
                      childFactory: nodeFactory,
                      grouping: {
                        groupGetter: Function.getter('data.group')
                      },
                      childNodes: getTestSet()
                    });
                    this.is(false, checkNode(node));

                    node.grouping.appendChild(node.grouping.firstChild);
                    this.is(false, checkNode(node));
                    node.grouping.appendChild(node.grouping.firstChild);
                    this.is(false, checkNode(node));
                    node.grouping.appendChild(node.grouping.firstChild);
                    this.is(false, checkNode(node));
                    node.grouping.appendChild(node.grouping.firstChild);
                    this.is(false, checkNode(node));

                    node.grouping.insertBefore(node.grouping.lastChild, node.grouping.firstChild);
                    this.is(false, checkNode(node));
                    node.grouping.insertBefore(node.grouping.lastChild, node.grouping.firstChild);
                    this.is(false, checkNode(node));
                    node.grouping.insertBefore(node.grouping.lastChild, node.grouping.firstChild);
                    this.is(false, checkNode(node));
                    node.grouping.insertBefore(node.grouping.lastChild, node.grouping.firstChild);
                    this.is(false, checkNode(node));

                    node.grouping.insertBefore(node.grouping.childNodes[1], node.grouping.childNodes[2]);
                    this.is(false, checkNode(node));
                    node.grouping.insertBefore(node.grouping.childNodes[1], node.grouping.childNodes[3]);
                    this.is(false, checkNode(node));
                    node.grouping.insertBefore(node.grouping.childNodes[1], node.grouping.childNodes[0]);
                    this.is(false, checkNode(node));
                    node.grouping.insertBefore(node.grouping.childNodes[2], node.grouping.childNodes[3]);
                    this.is(false, checkNode(node));
                    node.grouping.insertBefore(node.grouping.childNodes[3], node.grouping.childNodes[2]);
                    this.is(false, checkNode(node));
                    node.grouping.insertBefore(node.grouping.childNodes[3], node.grouping.childNodes[1]);
                    this.is(false, checkNode(node));
                  }
                },
                {
                  name: 'grouping & dataSource',
                  testcase: [
                    {
                      name: 'childNodes + group dataset',
                      test: function(){
                        var node = new Node({
                          childFactory: nodeFactory,
                          childNodes: getTestSet()
                        });

                        node.setGrouping({
                          groupGetter: Function.getter('data.groupObj'),
                          dataSource: groupDatasetByGroup
                        });
                        this.is(false, checkNode(node));

                        node.setGrouping();
                        this.is(false, checkNode(node));

                        node.setGrouping({
                          groupGetter: Function.getter('data.groupObj'),
                          dataSource: groupDatasetByGroup
                        });
                        this.is(false, checkNode(node));

                        node.grouping.setDataSource();
                        this.is(false, checkNode(node));
                      }
                    },
                    {
                      name: 'childNodes + group dataset #2',
                      test: function(){
                        var node = new Node({
                          childFactory: nodeFactory,
                          childNodes: getTestSet(),
                          grouping: {
                            groupGetter: Function.getter('data.groupObj')
                          }
                        });
                        this.is(false, checkNode(node));

                        node.grouping.setDataSource(groupDatasetByGroup);
                        this.is(false, checkNode(node));

                        node.setGrouping();
                        this.is(false, checkNode(node));

                      }
                    },
                    {
                      name: 'childNodes + empty group dataset + fill/clear the dataset',
                      test: function(){
                        var groupDataSource = new basis.data.Dataset();
                        var node = new Node({
                          childFactory: nodeFactory,
                          childNodes: getTestSet(),
                          grouping: {
                            groupGetter: Function.getter('data.groupObj'),
                            dataSource: groupDataSource
                          }
                        });
                        this.is(false, checkNode(node));

                        groupDataSource.add(groupDatasetByGroup.getItems());
                        this.is(false, checkNode(node));

                        groupDataSource.clear();
                        this.is(false, checkNode(node));
                      }
                    },
                    {
                      name: 'childNodes + empty group dataset + fill/clear the dataset + destroy dataset',
                      test: function(){
                        var groupDataSource = new basis.data.Dataset();
                        var node = new Node({
                          childFactory: nodeFactory,
                          childNodes: getTestSet(),
                          grouping: {
                            groupGetter: Function.getter('data.groupObj'),
                            dataSource: groupDataSource
                          }
                        });
                        this.is(false, checkNode(node));

                        groupDataSource.add(groupDatasetByGroup.getItems());
                        this.is(false, checkNode(node));

                        groupDataSource.destroy();
                        this.is(null, node.grouping.dataSource);
                        this.is(true, node.grouping.childNodes.length);
                        this.is(false, checkNode(node));

                        var dataset2 = new basis.data.Dataset({ items: groupDatasetByGroup.getItems() });
                        var itemCount = dataset2.itemCount;
                        this.is(true, itemCount > 0);

                        node.grouping.setDataSource(dataset2);
                        this.is(dataset2, node.grouping.dataSource);
                        this.is(itemCount, dataset2.itemCount);
                        this.is(false, checkNode(node));

                        node.clear();
                        this.is(dataset2, node.grouping.dataSource);
                        this.is(itemCount, dataset2.itemCount);
                        this.is(0, node.childNodes.length);
                        this.is(false, checkNode(node));
                      }
                    },
                    {
                      name: 'childNodes + group dataset 10',
                      test: function(){
                        var node = new Node({
                          childFactory: nodeFactory,
                          childNodes: getTestSet()
                        });

                        node.setGrouping({
                          groupGetter: Function.getter('data.groupObj'),
                          dataSource: groupDatasetByGroup10
                        });
                        this.is(false, checkNode(node));

                        node.setGrouping();
                        this.is(false, checkNode(node));

                        node.setGrouping({
                          groupGetter: Function.getter('data.groupObj'),
                          dataSource: groupDatasetByGroup10
                        });
                        this.is(false, checkNode(node));

                        node.grouping.setDataSource();
                        this.is(false, checkNode(node));

                      }
                    },
                    {
                      name: 'group dataset + child nodes on init',
                      test: function(){
                        var node = new Node({
                          childFactory: nodeFactory,
                          childNodes: getTestSet(),
                          grouping: {
                            groupGetter: Function.getter('data.groupObj'),
                            dataSource: groupDatasetByGroup
                          }
                        });
                        this.is(false, checkNode(node));

                        node.setGrouping();
                        this.is(false, checkNode(node));

                      }
                    },
                    {
                      name: 'group dataset + child nodes after init',
                      test: function(){
                        var node = new Node({
                          childFactory: nodeFactory,
                          grouping: {
                            groupGetter: Function.getter('data.groupObj'),
                            dataSource: groupDatasetByGroup
                          }
                        });
                        this.is(false, checkNode(node));

                        node.setChildNodes(getTestSet());
                        this.is(false, checkNode(node));

                        node.setChildNodes();
                        this.is(false, checkNode(node));
                      }
                    }
                  ]
                }
              ]
            }
          ]
        }
      ];

    })());


  </script>
</body>

</html>